package com.whity.towerdefense.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL10;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import com.whity.towerdefense.Utils;
import com.whity.towerdefense.view.GraphicEltFactory;


import android.graphics.Point;
import android.util.Log;

public class Level implements I_Tickable
{
	// =============================================================
	// Private attributs
	
	// Constants
	private static final String TAG = "com.djm.test03.model";
	
	// Game attributs
	private Map						m_Map;
	private String 					m_Name;
	private String 					m_MapPath;
	private static Vector<Wave>		m_Waves;
	private float					m_WavesFrequency; // Number of wave per second;
	private int						m_NextWaveTime;
	private int						m_NextWave;
	private PathfindingThread		m_PathThread;
	private static Vector<String> 	m_BaseTowerTypes;
	
	private int						m_TimeElapsed; // number of Ms since the begining of the level in Ms
	
	// =============================================================
	// Public functions :
	
	public Level(String p_GamePath)
	{
		m_Waves = new Vector<Wave>();
		m_WavesFrequency = 0.1f;
		m_NextWaveTime = (int) (1000/m_WavesFrequency);
		m_BaseTowerTypes = new Vector<String>();
		m_NextWave = 0;
		m_TimeElapsed = 0;
		try
		{
	        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
	        factory.setValidating(false);
	        XmlPullParser xmlParser = factory.newPullParser();
	        
	        InputStream raw = GameModel.ASSETS_MANAGER.open(p_GamePath);
	        xmlParser.setInput(raw, null);
	        
	        int eventType = xmlParser.getEventType();
	        while(eventType != XmlPullParser.END_DOCUMENT)
	        {
	            if(eventType == XmlPullParser.START_TAG)
	            {
	            	if(xmlParser.getName().equals("Level"))
	            	{
	            		m_Name = xmlParser.getAttributeValue(null, "Name");
	            		m_MapPath = xmlParser.getAttributeValue(null, "MapPath");
	            		
	            		if(m_Name == null)
	            			throw(new ParsingException("Miss attribut \"Name\" in Game mark"));
	            		
	            		if(m_MapPath == null)
	            			throw(new ParsingException("Miss attribut \"MapPath\" in Game mark"));
	            		
	            		m_Map = new Map(Utils.MAP_PATH + "/" + m_MapPath);
	            	}
	            	else if(xmlParser.getName().equals("Wave"))
	            	{
	            		Wave wave = new Wave(xmlParser);
	            		m_Waves.add(wave);
	            	}
	            	else if(xmlParser.getName().equals("Towers"))
	            	{
	            		LoadTowers(xmlParser);
	            	}
	            }
	            else if(eventType == XmlPullParser.END_TAG)
	            {

	            }
	            else if(eventType == XmlPullParser.TEXT)
	            {
	                
	            }
	            eventType = xmlParser.next();
	        }
	        
	        m_PathThread = new PathfindingThread(m_Map);
	        m_PathThread.start();
	    }
		catch (XmlPullParserException e)
	    {
	    	Log.w(TAG, "XmlParser exception for level " + m_Name + ":" + e.toString());
	    }
		catch (IOException e)
	    {
	    	Log.w(TAG, "IO exception for level " + m_Name + ":" + e.toString());
		} catch (ParsingException e)
		{
			Log.w(TAG, "Parser exception for level " + m_Name + ":" + e.toString());
		}	
	}
	
	public void LoadGraphism(GL10 p_GL)
	{
		GraphicEltFactory.LoadGraphism(p_GL);
	}
	
	public void UnloadGraphism(GL10 p_GL)
	{
		GraphicEltFactory.UnloadGraphism(p_GL);
	}
	
	public void StartNextWave()
	{
		if(m_NextWave >= 0 && m_NextWave < m_Waves.size())
		{
			Log.d(TAG, "Start wave number : " + m_NextWave);
			GameModel.GAME_THREAD.AddTickable(m_Waves.elementAt(m_NextWave));
			m_NextWave++;
		}
	}
	
	public Map GetMap()
	{
		return m_Map;
	}
	
	public Vector<String> GetBaseTowers()
	{
		return m_BaseTowerTypes;
	}

	public boolean GameTick(int p_Ms)
	{
		m_TimeElapsed += p_Ms;
		
		if(m_NextWave >= 0 && m_NextWave < m_Waves.size())
		{
			if(m_TimeElapsed > m_NextWaveTime)
			{
				StartNextWave();
				m_NextWaveTime += (int) (1000/m_WavesFrequency);
			}
		}
		return true;
	}
	
	public void RecalculatePathfinding()
	{
		for(Unit unit : m_Map.GetUnits())
		{
			m_PathThread.AddPathfindable(unit, m_Map.GetGoal());
		}
	}
	
	public void CalculatePath(I_Pathfindable p_Elt, Point p_Goal)
	{
		if(p_Goal != null)
		{
			m_PathThread.AddPathfindable(p_Elt, p_Goal);
		}
	}
	
	public void AddUnit(Unit p_Unit)
	{
		m_Map.AddUnit(p_Unit);
		GameModel.GAME_THREAD.AddTickable(p_Unit);
	}
	
	public void RemoveUnit(Unit p_Unit)
	{
		m_Map.RemoveUnit(p_Unit);
	}
	
	public void AddTower(Tower p_Tower)
	{
		m_Map.AddTower(p_Tower);
		GameModel.GAME_THREAD.AddTickable(p_Tower);
		RecalculatePathfinding();
	}
	
	public void AddShoot(Shoot p_Shoot)
	{
		m_Map.AddShoot(p_Shoot);
		GameModel.GAME_THREAD.AddTickable(p_Shoot);
	}
	
	public void RemoveShoot(Shoot p_Shoot)
	{
		m_Map.RemoveShoot(p_Shoot);
	}
	
	public String SaveToXml()
	{
		String res = "";
		
		// TODO Implement save
		
		return res;
	}
	
	// =============================================================
	// Private function
	
	private void LoadTowers(XmlPullParser p_XmlParser) throws XmlPullParserException, IOException, ParsingException
	{
		if(p_XmlParser.getName().equals("Towers"))
		{
			int eventType = p_XmlParser.getEventType();
			
			while(eventType != XmlPullParser.END_TAG || !p_XmlParser.getName().equals("Towers"))
			{
				if(eventType == XmlPullParser.START_TAG && p_XmlParser.getName().equals("Tower"))
				{
					String towerPath = p_XmlParser.getAttributeValue(null, "TowerPath");
					
					XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			        factory.setValidating(false);
			        XmlPullParser towerXmlParser = factory.newPullParser();
			        InputStream raw = GameModel.ASSETS_MANAGER.open(Utils.TOWER_PATH + "/" + towerPath);
			        towerXmlParser.setInput(raw, null);
			        
			        towerXmlParser.next();
			        m_BaseTowerTypes.add(TowerFactory.CreateNewType(towerXmlParser));
				}
				eventType = p_XmlParser.next();
			}
		}
		else
		{
			Log.w(TAG, "Can't load towers with the xml tag: " + p_XmlParser.getName());
		}
		
		if(m_BaseTowerTypes.size()>4)
		{
			Log.w(TAG, "Only the first 4 types pf tower will be used.");
			while(m_BaseTowerTypes.size()>4)
			{
				m_BaseTowerTypes.remove(4);
			}
		}
	}
	
	// =============================================================
}
